#include "ModelBuilder.h"
#include <boost/foreach.hpp>

namespace GenParser
{
	SemanticModelBuilder::SemanticModelBuilder(SemanticModel::ModelPtr model)
		: _model(model)
	{
	}
	
	void SemanticModelBuilder::operator()(EmptyItem const& inheritance) const
	{
	}
	
	void SemanticModelBuilder::addOperations(const std::wstring& essenseName,
		const std::vector<SingleOperationDef>& operations, bool isAbstract) const
	{
		_model->addEssense(essenseName.c_str());
		BOOST_FOREACH(const SingleOperationDef& operation, operations)
		{
			_model->addOperation(operation.OperationName.c_str());
			_model->addRelation(essenseName.c_str(), 
				SemanticModel::Relation(isAbstract 
					? SemanticModel::SpecifyRelation
					: SemanticModel::CanRelation), 
				operation.OperationName.c_str());
			BOOST_FOREACH(const std::wstring& participant, operation.Participants)
			{
				_model->addEssense(participant.c_str());
				_model->addRelation(operation.OperationName.c_str(), 
					SemanticModel::Relation(SemanticModel::UsesRelation), 
					participant.c_str());
			}
		}
	}

	void SemanticModelBuilder::operator()(OperationsDef const& operations) const
	{
		addOperations(operations.EssenseName, operations.Operations, false);
	}

	void SemanticModelBuilder::operator()(AbstractOperationsDef const& operations) const
	{
		addOperations(operations.EssenseName, operations.AbstractOperations, true);
	}

	void SemanticModelBuilder::operator()(GeneralizationDef const& inheritance) const
	{
		connectEssenses(inheritance.EssenseName, SemanticModel::IsRelation, 
			inheritance.SubessenseName);
	}

	void SemanticModelBuilder::operator()(ImplementationDef const& implementation) const
	{
		connectEssenses(implementation.EssenseName, 
			SemanticModel::ImplementationRelation, 
			implementation.InterfaceName);
	}

	void SemanticModelBuilder::operator()(ContainsDef const& contains) const
	{
		connectEssenses(contains.EssenseName, 
			SemanticModel::ContainsRelation, 
			contains.PartEssenses);		
	}
	
	void SemanticModelBuilder::connectEssenses(const std::vector<std::wstring>& essenseNamesA,
			SemanticModel::RelationType relationType,
			const std::vector<std::wstring>& essenseNamesB) const
	{	
		for (std::vector<std::wstring>::const_iterator i = 
			essenseNamesA.begin(); i != essenseNamesA.end(); ++i)
		{
			const std::wstring& essenseNameA = *i;
			_model->addEssense(essenseNameA.c_str());
			for (std::vector<std::wstring>::const_iterator j = 
				essenseNamesB.begin(); j != essenseNamesB.end(); ++j)
			{
				const std::wstring& essenseNameB = *j;
				_model->addEssense(essenseNameB.c_str());
				_model->addRelation(essenseNameA.c_str(), relationType, essenseNameB.c_str());
			}
		}
	}

	void SemanticModelBuilder::operator()(CompositionDef const& composition) const
	{
		connectEssenses(composition.Leafs,
			SemanticModel::ImplementationRelation,
			composition.CompositionName);
			
		std::wstring compositeBase = composition.CompositionName + L"Composite";
		connectEssenses(compositeBase,
			SemanticModel::ImplementationRelation,
			composition.CompositionName);
			
		std::vector<SingleOperationDef> operations;
		{
			SingleOperationDef add;
			add.OperationName = L"addChild";
			add.Participants.push_back(composition.CompositionName);
			operations.push_back(add);
		}
		{
			SingleOperationDef remove;
			remove.OperationName = L"removeChild";
			remove.Participants.push_back(composition.CompositionName);
			operations.push_back(remove);
		}
		{
			SingleOperationDef child;
			child.OperationName = L"child";
			child.Participants.push_back(L"string");
			operations.push_back(child);
		}
		addOperations(compositeBase, operations, false);
			
		connectEssenses(composition.Composites,
			SemanticModel::ImplementationRelation,
			compositeBase);
	}

}